package com.eat.netty_server.netty;

import com.eat.netty_server.hander.InHander;
import com.eat.netty_server.hander.MessageCodec;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.logging.LoggingHandler;
import org.springframework.stereotype.Component;


/**
 * @author CZF
 * @create 2022-03-29 14:31
 *
 * 模拟鱼缸网络通信的服务端
 */

//放入spring容器中
@Component
public class NettyServer {

    //启动netty服务端
    public void start(int port) throws InterruptedException {


        //创建BossGroup 和 WorkerGroup
        EventLoopGroup bossGroup = new NioEventLoopGroup(); //只处理连接请求，交给workerGroup来处理业务
        EventLoopGroup workerGroup = new NioEventLoopGroup(); //真正和客户端业务处理

        try {


            //创建netty服务器端的启动对象，用来配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();

            //链式编程配置参数
            bootstrap.group(bossGroup, workerGroup) //设置两个线程组
                    .channel(NioServerSocketChannel.class)  //使用NioSocketChannel 作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列等待连接的个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true) //设置保持活动连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() { //创建一个通道初始化对象（匿名对象）
                        //给pipeline 设置处理器
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
                                    .addLast(new LoggingHandler()) //日志handler
                                    .addLast(new FixedLengthFrameDecoder(60)) //解决粘包半包，固定长度的协议数据包，所以用固定长度解码器handler
                                    .addLast(new MessageCodec()) //编解码器
                                    .addLast(new InHander());
                        }
                    }); //给workerGroup 的 EventLoop 对应的管道设置处理器

            System.out.println("netty服务端准备好！");


            //绑定一个端口并且同步，生产了一个ChannelFuture 对象
            //启动netty服务器（并绑定端口）
            ChannelFuture cf = bootstrap.bind(port).sync();
            //对关闭通道进行监听
            cf.channel().closeFuture().sync();

        } finally { //如果出现异常，则关闭（不管什么异常）
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();

        }

    }
}
